# src/service/chat_service.py
import logging
from typing import Optional, List, Dict, Any, AsyncGenerator

from langchain_core.messages import BaseMessage, HumanMessage, AIMessage

from src.service.session_service import SessionService
from src.database.db import SessionLocal
from src.llm_clients.deepseek_client import DeepSeekLLMClient

logger = logging.getLogger(__name__)

class ChatService:
    """
    服务类，用于处理纯聊天模式下的交互。
    """
    def __init__(self):
        """
        初始化 ChatService。
        会尝试初始化 DeepSeekLLMClient。如果API密钥未配置，deepseek_llm 将为 None。
        """
        try:
            self.deepseek_llm = DeepSeekLLMClient()
            logger.info("ChatService: DeepSeekLLMClient 初始化成功。")
        except ValueError as e: # DeepSeekLLMClient 在 API Key 未配置时会抛出 ValueError
            logger.error(f"ChatService: DeepSeekLLMClient 初始化失败: {e}. 聊天模式可能无法工作。")
            self.deepseek_llm = None

    async def run_simple_chat(
        self,
        session_id: str,
        # user_input_content: str, # 改为接收完整的 user_input_message 对象
        user_input_message: Dict[str, str], # 例如: {"role": "user", "content": "你好"}
        username: Optional[str] = None
    ) -> AsyncGenerator[Dict[str, Any], None]:
        """
        运行一个简单的聊天回合。

        参数:
            session_id: 当前会话的ID。
            user_input_message: 当前用户输入的消息对象 (例如 {"role": "user", "content": "你好"})。
            username: 当前用户名。

        返回:
            一个异步生成器，逐块产生事件和数据。
        """
        if not self.deepseek_llm:
            yield {"event": "error", "data": "聊天服务未正确初始化 (DeepSeek客户端问题，请检查API密钥)。"}
            return

        db = SessionLocal()
        try:
            current_user_content = user_input_message.get("content", "")
            if not current_user_content:
                 yield {"event": "error", "data": "用户输入内容不能为空。"}
                 return

            # 1. 获取历史消息 (不包括当前这条用户输入)
            # SessionService.get_formatted_langchain_messages 通常返回的是到上一轮为止的消息
            # 或者，如果它包含了当前消息，我们需要调整这里的逻辑。
            # 假设它返回的是直到上一轮为止的历史。
            history_langchain_messages: List[BaseMessage] = await SessionService.get_formatted_langchain_messages(
                db, session_id, username
            )
            
            # 2. 将LangChain消息转换为LLM期望的字典格式，并添加当前用户消息
            # 注意：get_formatted_langchain_messages 返回的是 LangChain BaseMessage 对象列表
            # 我们需要将它们转换为 DeepSeek API (OpenAI SDK 格式) 期望的字典列表。
            llm_messages: List[Dict[str, str]] = []
            for msg in history_langchain_messages:
                role = "user" # 默认
                if isinstance(msg, HumanMessage):
                    role = "user"
                elif isinstance(msg, AIMessage):
                    role = "assistant"
                # LangChain 的 SystemMessage 通常用于指示LLM行为，可以根据需要决定是否直接传递
                # 对于DeepSeek，如果SystemMessage是对话历史的一部分，可以转换为 "system" role
                # 但通常，一个全局的 system prompt 会在 messages 列表的开头
                # 这里我们假设历史中的 SystemMessage (如果是AIMessage转换来的) 应该作为 assistant
                # 或者，如果 get_formatted_langchain_messages 正确处理了 system role 为 AIMessage(name="system")
                # 那么这里 AIMessage 的 role 应该被视为 "assistant"

                # 过滤掉内容为空的消息，以防意外
                if msg.content and isinstance(msg.content, str) and msg.content.strip():
                    llm_messages.append({"role": role, "content": msg.content})
            
            # 添加当前用户消息
            llm_messages.append({"role": user_input_message.get("role", "user"), "content": current_user_content})
            
            logger.info(f"聊天模式: 为会话 {session_id} 构建了 {len(llm_messages)} 条消息发送给LLM。")
            # logger.debug(f"聊天模式: 发送给LLM的消息: {llm_messages}") # 仅调试时开启

            # 3. 调用大模型流式接口
            full_ai_response_content = ""
            last_chunk = None
            async for chunk in self.deepseek_llm.chat_stream(llm_messages):
                # 直接将从 deepseek_llm.chat_stream 收到的块传递出去
                yield chunk
                last_chunk = chunk  # 保存最后一个块以便后续引用
                if chunk.get("event") == "text" and isinstance(chunk.get("data", ""), str):
                    full_ai_response_content += chunk.get("data", "")
            
            # 检查最后一个块是否是错误
            if last_chunk and last_chunk.get("event") == "error": 
                logger.error(f"聊天模式: DeepSeek流返回错误: {last_chunk.get('data')}")
                # 错误已经通过 yield chunk 传递出去了，这里不需要重复 yield
                return # 提前返回，不保存AI响应

            if not full_ai_response_content.strip():
                logger.warning(f"聊天模式: LLM没有为会话 {session_id} 返回有效文本内容。")
                # 可以选择 yield 一个特定的事件，或者静默处理
                # yield {"event": "info", "data": "AI未返回有效响应。"}
                # 即使AI回复为空，也可能需要保存一个空的assistant消息，表示AI已响应
                # 但这里我们选择不保存空回复，除非业务明确要求
            else:
                # 4. 将AI的完整回复存入数据库
                # 使用正确的 add_message 方法
                await SessionService.add_message(
                    db=db,
                    session_id=session_id,
                    content=full_ai_response_content,
                    role="assistant", # AI的回复角色
                    message_type="text", # 消息类型
                    username=username # 记录是哪个用户触发的
                )
                db.commit() # 提交数据库事务
                logger.info(f"聊天模式: AI回复已保存到会话 {session_id}。长度: {len(full_ai_response_content)}")
                # （可选）发送一个最终事件表明AI回复已保存
                yield {"event": "final_response_saved", "data": {"message_id": "id_from_db_if_available"}}


        except Exception as e:
            logger.exception(f"聊天模式处理失败 (会话 {session_id}): {e}")
            yield {"event": "error", "data": f"聊天模式发生内部错误: {str(e)}"}
        finally:
            if db:
                db.close()
